package com.gitee.target123.develop.pay.util;

import com.alipay.api.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.gitee.target123.develop.pay.ali.AliPay;
import com.gitee.target123.develop.pay.ali.AliPayTradeType;
import com.gitee.target123.develop.pay.model.OrderAliPayInfo;
import com.gitee.target123.develop.pay.model.OrderCheckResult;
import com.gitee.target123.develop.pay.model.OrderWxPayInfo;
import com.gitee.target123.develop.pay.wx.WxPay;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

public class PayUtil {

    /**
     * 微信统一下单
     * @param wxPay 微信支付操作对象
     * @param request 请求对象
     */
    public static OrderWxPayInfo wxPayInfo(WxPay wxPay, WxPayUnifiedOrderRequest request) throws WxPayException {
        WxPayService wxPayService = wxPay.getWxPayService();
        WxPayUnifiedOrderResult unifiedOrderResult = wxPayService.unifiedOrder(request);
        if(WxPayConstants.ResultCode.SUCCESS.equals(unifiedOrderResult.getReturnCode())) { // 成功
            String prepayId = unifiedOrderResult.getPrepayId();
            Instant now = Instant.now();
            String timeStamp = String.valueOf(now.getEpochSecond());
            String nonceStr = String.valueOf(now.toEpochMilli());
            String appId = wxPay.getWxPayProperties().getAppId();
            String signType = request.getSignType()!=null ? request.getSignType(): WxPayConstants.SignType.MD5;

            OrderWxPayInfo payInfo = new OrderWxPayInfo();
            if (WxPayConstants.TradeType.APP.equals(request.getTradeType())) {
                // APP支付绑定的是微信开放平台上的账号，APPID为开放平台上绑定APP后发放的参数
                // 此map用于参与调起sdk支付的二次签名,格式全小写，timestamp只能是10位,格式固定，切勿修改
                Map<String, String> configMap = new HashMap<>(6);
                String partnerId = wxPay.getWxPayProperties().getMchId();
                String packageValue = "Sign=WXPay";
                configMap.put("appid", appId);
                configMap.put("partnerid", partnerId);
                configMap.put("prepayid", prepayId);
                configMap.put("package", packageValue);
                configMap.put("noncestr", nonceStr);
                configMap.put("timestamp", timeStamp);

                OrderWxPayInfo.App app = new OrderWxPayInfo.App();
                app.setAppId(appId);
                app.setTimeStamp(timeStamp);
                app.setNonceStr(nonceStr);
                app.setPackageValue(packageValue);
                app.setPartnerId(partnerId);
                app.setPrepayId(prepayId);
                app.setSign(SignUtils.createSign(configMap, signType, wxPay.getWxPayProperties().getMchKey(), null));
                payInfo.setApp(app);
            }else if (WxPayConstants.TradeType.JSAPI.equals(request.getTradeType())){
                Map<String, String> configMap = new HashMap<>(5);
                String packageValue = "prepay_id=" + prepayId;
                configMap.put("appId", appId);
                // 支付签名时间戳，注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                configMap.put("timeStamp", timeStamp);
                configMap.put("nonceStr", nonceStr);
                configMap.put("package", packageValue);
                configMap.put("signType", signType);

                OrderWxPayInfo.JsApi jsApi = new OrderWxPayInfo.JsApi();
                jsApi.setAppId(appId);
                jsApi.setTimeStamp(timeStamp);
                jsApi.setNonceStr(nonceStr);
                jsApi.setPackageValue(packageValue);
                jsApi.setSignType(signType);
                jsApi.setPaySign(SignUtils.createSign(configMap, signType, wxPay.getWxPayProperties().getMchKey(), null));
                payInfo.setJsApi(jsApi);
            }else if (WxPayConstants.TradeType.NATIVE.equals(request.getTradeType())){
                OrderWxPayInfo.NativeScan nativeScan = new OrderWxPayInfo.NativeScan();
                nativeScan.setCodeUrl(unifiedOrderResult.getCodeURL());
                payInfo.setNativeScan(nativeScan);
            }else if (WxPayConstants.TradeType.MWEB.equals(request.getTradeType())){
                OrderWxPayInfo.Mweb mweb = new OrderWxPayInfo.Mweb();
                mweb.setMwebUrl(unifiedOrderResult.getMwebUrl());
                payInfo.setMweb(mweb);
            }
            return payInfo;
        }else {
            throw new WxPayException(unifiedOrderResult.toString());
        }
    }

    /**
     * 微信回调验证
     * @param wxPay 微信支付操作对象
     * @param xmlData 回调参数
     * @see WxPayConstants.ResultCode
     */
    public static OrderCheckResult wxCheck(WxPay wxPay, String xmlData) throws WxPayException {
        WxPayService wxPayService = wxPay.getWxPayService();
        WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlData);

        OrderCheckResult checkResult = new OrderCheckResult();
        checkResult.setOrderTrade(result.getOutTradeNo());
        BigDecimal money = new BigDecimal(result.getTotalFee()).divide(new BigDecimal(100));
        checkResult.setOrderMoney(money);
        if (WxPayConstants.ResultCode.SUCCESS.equals(result.getResultCode())){
            checkResult.setPaySuccess(true);
        }else {
            checkResult.setPaySuccess(false);
            checkResult.setErrorMsg("微信支付结果失败:"+result.getErrCode() + "=" + result.getErrCodeDes());
        }
        return checkResult;
    }

    /**
     * 支付宝下单
     * @param aliPay 支付宝支付操作对象
     * @param request 请求对象
     * @param type 支付类型
     */
    public static <T extends AlipayResponse> OrderAliPayInfo aliPayInfo(AliPay aliPay, AlipayRequest<T> request, AliPayTradeType type) throws AlipayApiException {
        AlipayClient alipayClient = aliPay.getAlipayClient();
        T response;
        if (type == AliPayTradeType.SDK){
            response = alipayClient.sdkExecute(request);
        }else if (type == AliPayTradeType.PAGE){
            response = alipayClient.pageExecute(request);
        }else {
            throw new AlipayApiException("参数错误");
        }

        if(response.isSuccess()){
            OrderAliPayInfo aliPayInfo = new OrderAliPayInfo();
            aliPayInfo.setBody(response.getBody());
            return aliPayInfo;
        }
        throw new AlipayApiException("下单失败");
    }

    /**
     * 支付宝回调验证
     * @param aliPay 支付宝支付操作对象
     * @param params 回调参数
     * @return 是否成功支付
     * @throws AlipayApiException 抛异常执行回滚操作
     */
    public static OrderCheckResult aliCheck(AliPay aliPay, Map<String, String> params) throws AlipayApiException {
        boolean flag = AlipaySignature.rsaCheckV1(params,aliPay.getAliPayProperties().getPublicKey(),AlipayConstants.CHARSET_UTF8,AlipayConstants.SIGN_TYPE_RSA2);
        if (flag) {
            String app_id = params.get("app_id");
            String seller_id = params.get("seller_id");
            String trade_status = params.get("trade_status");
            // 验证商户
            if (aliPay.getAliPayProperties().getAppId().equals(app_id) && aliPay.getAliPayProperties().getSellerId().equals(seller_id)){
                OrderCheckResult checkResult = new OrderCheckResult();
                checkResult.setOrderTrade(params.get("out_trade_no"));
                checkResult.setOrderMoney(new BigDecimal(params.get("total_amount")));
                checkResult.setPaySuccess("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status));
                return checkResult;
            }
        }
        throw new AlipayApiException("支付宝支付验证失败");
    }

    /**
     * 微信企业付款
     * @param wxPay 微信支付操作对象
     * @param entPayRequest 请求对象
     * @throws WxPayException 抛异常执行回滚操作
     */
    public static EntPayResult wxEntPay(WxPay wxPay, EntPayRequest entPayRequest) throws WxPayException {
        WxPayService wxPayService = wxPay.getWxPayService();
        return wxPayService.getEntPayService().entPay(entPayRequest);
    }

    /**
     * 支付宝单笔转账
     * @param aliPay 支付宝支付操作对象
     * @param request 请求对象
     * @throws AlipayApiException 抛异常执行回滚操作
     */
    public static AlipayFundTransToaccountTransferResponse aliTransfer(AliPay aliPay, AlipayFundTransToaccountTransferRequest request) throws AlipayApiException {
        AlipayClient alipayClient = aliPay.getAlipayClient();
        return alipayClient.execute(request);
    }

}
